﻿using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using CI.Interfaces;

namespace CI.Organism
{
    /// <summary>Collection class containing the list of the requirments</summary>
    [CollectionDataContract]
    public class RequirementCollection : List<IRequirement>, IRequirementCollection
    {
        /// <summary>
        /// Take this parent Requirements and create a new requirement collection to be put in the new child organism
        /// Mutate the current requirements and return a new one, deep class level mutation
        /// </summary>
        /// <param name="mutationRate">mutation rate to be applied</param>
        /// <param name="childOrganism">child Organism it will be going into</param>
        /// <returns>new requirements for child</returns>
        public IRequirementCollection Mutate(double mutationRate, IOrganism childOrganism)
        {
            #region Argument check
            if (childOrganism == null)
                throw new ArgumentException("Organism");
            #endregion

            // make a new requirement list
            var childRequirements = new RequirementCollection();

            // mutate all the requirements
            foreach (IRequirement requirement in this)
            {
                childRequirements.Add(requirement.Mutate(mutationRate, childOrganism));
            }

            // mutate adding new requirements to the collection
            if (Mutation.MutateState(mutationRate))
            {
                // add a new one
                childRequirements.Add(Requirement.CreateNewRequirement(mutationRate, childOrganism));
            }

            // mutate removing some requirements
            if (Mutation.MutateState(mutationRate) && (childRequirements.Count > 0))
            {
                childRequirements.RemoveRange(Mutation.CollectionSelect(childRequirements), 1);
            }

            // if the previous list is empty we have to have at least one so create it
            if (childRequirements.Count == 0)
                childRequirements.Add(Requirement.CreateNewRequirement(mutationRate, childOrganism));

            return childRequirements;
        }

        /// <summary>
        /// Find the requirement with the specifed guid
        /// </summary>
        /// <param name="guid">guid to find</param>
        /// <returns>requirement</returns>
        public IRequirement Find(Guid guid)
        {
            return FindLast(requirement => requirement.Guid == guid);
        }
    }
}